OS: Windows 10
Editor: Visual Studio Code
Rust version: 1.63.0
今天簡單了解一下Rust中的泛型,真的是簡單而已,因為後面還有一個看整天感覺熟悉,但又很陌生的功能-特徵(trait),但以下的內容還是會牽扯到特徵的功能。
如同其他語言,在邏輯上可能做一樣的事,例如比大小找出最大值,但因為型別不同需要,寫出出各自的版本,這時就會使用泛型。
以找出序列中的最大值為例,這是範例資料:
let list = vec![2.0, 2.5, 1.0, 0.9, 3.2];
let max_in_list = max(&list);
println!("Max in list: {}", max_in_list);
這是功能實作
fn max<T>(list: &[T]) -> T {
let mut max = list[0];
for &item in list {
if item > max {
max = item;
}
}
max
}
執行的會,compiler會丟出一段錯誤:
Compiling basic v0.1.0 (D:\projects\rust_learning\basic)
error[E0369]: binary operation `>` cannot be applied to type `T`
--> src\main.rs:36:17
|
36 | if item > max {
| ---- ^ --- T
| |
| T
|
help: consider restricting type parameter `T`
|
33 | fn max<T: std::cmp::PartialOrd>(list: &[T]) -> T {
| ++++++++++++++++++++++
For more information about this error, try `rustc --explain E0369`.
內容是說,如果要比大小,泛型的型別是要有實作>
符號,也就是錯誤訊息提到的std::cmp::PartialOrd
特徵。
所以改成這樣,有點像C#
的where
來限制可用的型別:
fn max<T: PartialOrd>(list: &[T]) -> T {
let mut max = list[0];
for &item in list {
if item > max {
max = item;
}
}
max
}
但還是會跟你抱怨錯誤:
Compiling basic v0.1.0 (D:\projects\rust_learning\basic)
error[E0508]: cannot move out of type `[T]`, a non-copy slice
--> src\main.rs:34:19
|
34 | let mut max = list[0];
| ^^^^^^^
| |
| cannot move out of here
| move occurs because `list[_]` has type `T`, which does not implement the `Copy` trait
| help: consider borrowing here: `&list[0]`
error[E0507]: cannot move out of a shared reference
--> src\main.rs:35:18
|
35 | for &item in list {
| ----- ^^^^
| ||
| |data moved here
| |move occurs because `item` has type `T`, which does not implement the `Copy` trait
| help: consider removing the `&`: `item`
Some errors have detailed explanations: E0507, E0508.
For more information about an error, try `rustc --explain E0507`.
compiler告訴我們,型別若沒有實作Copy
,則資料的所有權會發生問題,我們就照compiler的建議,再加上限制,有實作Copy
的型別才能使用,這時我們使用+
來限制:
fn max<T: PartialOrd + Copy>(list: &[T]) -> T {
let mut max = list[0];
for &item in list {
if item > max {
max = item;
}
}
max
}
之前就很常在用了,例如向量(vector)跟雜湊表(hash map)就是泛型的型別,下面示範如何定義泛型型別:
struct Point<T> {
x: T,
y: T,
}
如果要定義泛型型別的方法(methods):
impl<T> Point<T> {
fn move_to(&mut self, nx: T, ny: T) {
self.x = nx;
self.y = ny;
}
}
// example
let mut p = Point { x: 1.0, y: 2.0 };
p.move_to(15.0, 13.0);
然後,假如只指定一些泛型可以用,例如:
impl Point<bool> {
fn reset(&mut self) {
self.x = false;
self.y = false;
}
}
上面的例子就會是,當Point<T>
是用bool
型別的時候,才能使用reset
。
let mut pbool = Point { x: true, y: false };
pbool.reset();
let mut p = Point { x: 1.0, y: 2.0 };
p.reset();
錯誤訊息:
Compiling basic v0.1.0 (D:\projects\rust_learning\basic)
error[E0599]: no method named `reset` found for struct `Point<{float}>` in the current scope
--> src\main.rs:48:7
|
3 | struct Point<T> {
| --------------- method `reset` not found for this
...
48 | p.reset();
| ^^^^^ method not found in `Point<{float}>`
|
= note: the method was found for
- `Point<bool>`
For more information about this error, try `rustc --explain E0599`.
compiler會告訴你只有Point<bool>
有reset
的實作。